package service

import (
	"context"
	"errors"
	"fmt"
	"mini-app/config/redis"
	"mini-app/internal/app/admin/service"
	"mini-app/internal/app/grpc/client"
	"mini-app/internal/app/grpc/protoc/devicec"
	"mini-app/internal/app/grpc/protoc/sale_adminc"
	"mini-app/internal/app/grpc/protoc/system_admin"
	"mini-app/internal/dal"
	"mini-app/internal/dao"
	"mini-app/internal/define"
	"mini-app/internal/models"
	"mini-app/internal/pkg"
	"strconv"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"gorm.io/gorm"
)

type User struct{}

// 登录获取openid
func (User) Login(ctx context.Context, code, salesID string) (token, phone string, err error) {
	miniSDK, err := pkg.MiniProgram{}.New()
	if err != nil {
		return
	}
	rsp, err := miniSDK.GetAuth().Code2Session(code)
	if err != nil || rsp.ErrCode != 0 {
		return "", "", errorx.New("登录授权失败", -1)
	}

	// openid及sesion_key存入redis
	rdb := redis.NewDB()
	token = helper.Md5(strconv.Itoa(int(time.Now().UnixNano())) + helper.RandString(32))
	rdb.Set(ctx, define.MiniAppSessionOpenid+token, rsp.OpenID, time.Duration(2*24)*time.Hour).Result()  // openid
	rdb.Set(ctx, define.MiniAppSessionKey+token, rsp.SessionKey, time.Duration(2*24)*time.Hour).Result() // 会话密钥session_key

	var channelID string
	cli, err := client.GetAdminClient()
	if cli != nil && err == nil {
		deviceDetail, err := cli.DeviceDetail(ctx, &devicec.DeviceDetailReq{IdentificationCode: salesID})
		if err == nil && deviceDetail.Device != nil {
			// 渠道信息
			channelID, err = service.PromotionChannel{}.GetChannelByRobotID(ctx, dal.Q, deviceDetail.Device.RobotId)
			if err != nil {
				channelID = ""
			}
		}
	}
	// 用户信息写入表中
	success, _ := rdb.SetNX(ctx, define.RedisMiniUserCreateLock+rsp.OpenID, 1, time.Second*1).Result()
	if !success {
		time.Sleep(time.Second * 1)
	}
	userInfo, userErr := dao.User{}.UserInfo(ctx, dal.Q, rsp.OpenID, "", "")
	if userErr != nil || userInfo == nil {
		dao.User{}.Create(ctx, dal.Q, rsp.OpenID, channelID)
		phone = ""
	} else {
		if channelID != "" && userInfo.ChannelID == "" {
			dao.User{}.UpdateChannelID(ctx, dal.Q, rsp.OpenID, channelID)
		}
		phone = userInfo.Phone
	}
	return
}

// 获取手机号
func (User) GetPhoneNumber(ctx context.Context, openid, code string) (phone string, err error) {
	miniSDK, err := pkg.MiniProgram{}.New()
	if err != nil {
		return
	}

	// PhoneNumber     手机号（国外手机号会有区号）
	// PurePhoneNumber 无区号的手机号
	phoneRsp, phoneErr := miniSDK.GetAuth().GetPhoneNumber(code)
	if phoneErr != nil || phoneRsp == nil || phoneRsp.ErrCode != 0 {
		logx.Error(context.Background(), "获取手机号失败", logx.Any("phoneErr", phoneErr))
		// 已经存在手机号的直接返回
		userInfo, _ := dao.User{}.UserInfo(ctx, dal.Q, openid, "", "")
		if userInfo != nil && userInfo.Phone != "" {
			return userInfo.Phone, nil
		}
		err = errorx.New("手机号获取失败", define.ErrPhoneGetFailed)
		return
	}

	// 查询用户信息
	userInfo, err := dao.User{}.UserInfo(ctx, dal.Q, openid, "", "")
	if err != nil || userInfo == nil {
		err = errorx.New("用户信息不存在")
		return
	}
	// 保存手机号
	err = dao.User{}.UpdatePhone(ctx, dal.Q, openid, phoneRsp.PhoneInfo.PurePhoneNumber)
	return phoneRsp.PhoneInfo.PurePhoneNumber, err
}

// 用户信息
func (User) Profile(ctx context.Context, openid string) (res *models.User, err error) {
	res, err = dao.User{}.UserInfo(ctx, dal.Q, openid, "", "")
	return
}

func (User) ProfileBy(ctx context.Context, openid, userID, phone string) (res *models.User, err error) {
	res, err = dao.User{}.UserInfo(ctx, dal.Q, openid, userID, phone)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil
		}
		return
	}
	return
}

// 用户注销
func (User) Del(ctx context.Context, openid string) (err error) {
	userInfo, err := dao.User{}.UserInfo(ctx, dal.Q, openid, "", "")
	if err != nil || userInfo == nil {
		err = errorx.New("用户信息不存在")
		return
	}
	dao.User{}.Del(ctx, dal.Q, openid)
	return
}

// 用户信息编辑
func (User) Save(
	ctx context.Context,
	openid, nickName, phone string,
	gender int,
	birth, address, email, hobby, image string,
	userName, telNumber, postalCode, provinceName, cityName, countyName, streetName, detailAddress string,
) (err error) {
	userInfo, err := dao.User{}.UserInfo(ctx, dal.Q, openid, "", "")
	if err != nil || userInfo == nil || userInfo.ID == "" {
		return errorx.New("用户信息不存在", -1)
	}
	if image != "" && image != userInfo.Image {
		SystemAdminClient, clientErr := client.GetSystemAdminClient()
		if clientErr != nil {
			return
		}
		//文件确认
		var req system_admin.ConfirmFileReq
		req.FileUrl = image
		res, err1 := SystemAdminClient.ConfirmFile(context.Background(), &req)
		if err1 != nil && res.Code != 0 {
			logx.Error(context.Background(), "confirm file error", logx.Any("res", res), logx.Any("err", err1.Error()))
			return
		}
		// 文件删除
		SystemAdminClient.DeleteFile(context.Background(), &system_admin.DeleteFileReq{FileUrl: userInfo.Image})
		image = res.FileUrl
	}
	err = dao.User{}.Save(
		ctx,
		dal.Q,
		openid, nickName, phone,
		gender,
		birth, address, email, hobby, image,
		userName, telNumber, postalCode, provinceName, cityName, countyName, streetName, detailAddress,
	)
	return
}

func (User) GetWanXiangMember(ctx context.Context, openid string) (res *sale_adminc.GetWanXiangMemberRsp_Data, err error) {
	cli, err := client.GetSaleAdminClient()
	if cli != nil && err == nil {
		rsp, err := cli.GetWanXiangMember(ctx, &sale_adminc.GetWanXiangMemberReq{
			Openid: openid,
		})
		if err != nil || rsp.Code != 0 {
			return nil, errorx.New(rsp.Msg, int(rsp.Code))
		}
		return rsp.Data, errorx.New("获取万象会员信息成功", 0)
	}
	err = errorx.New("获取万象会员信息失败", 100099)
	return nil, err
}

func (User) GetWanXiangPoints(ctx context.Context, openid, mallcode string) (res *sale_adminc.GetWanXiangMemberRsp_Data, err error) {
	cli, err := client.GetSaleAdminClient()
	if cli != nil && err == nil {
		rsp, err := cli.GetWanXiangPoints(ctx, &sale_adminc.GetWanXiangPointsReq{
			Openid:   openid,
			Mallcode: mallcode,
		})
		if err != nil || rsp.Code != 0 {
			return nil, errorx.New(rsp.Msg, int(rsp.Code))
		}
		return rsp.Data, errorx.New("获取万象会员积分成功", 0)
	}
	err = errorx.New("获取万象会员积分失败", 100099)
	return nil, err
}

func (User) ReverseWanXiangPoints(ctx context.Context, orderID, openid string, points float64, points_id string, pay_univalent float64, mall_code string) (res *sale_adminc.PointsReverseRsp, err error) {
	cli, err := client.GetSaleAdminClient()

	logx.Info(context.Background(), "ReverseWanXiangPoints", logx.Any("openid", fmt.Sprint(openid)))
	if cli != nil && err == nil {
		rsp, err := cli.PointsReverse(ctx, &sale_adminc.PointsReverseReq{
			Points:   float32(points),
			PointsId: points_id,
			Orderid:  orderID,
			Openid:   openid,
			Mallcode: mall_code,
		})
		logx.Info(context.Background(), "ReverseWanXiangPoints", logx.Any("rsp.Code", fmt.Sprint(rsp.Code)))
		logx.Info(context.Background(), "ReverseWanXiangPoints", logx.Any("rsp.Msg", fmt.Sprint(rsp.Msg)))
		if err != nil || rsp.Code != 0 {
			return nil, errorx.New(rsp.Msg, int(rsp.Code))
		}
		return rsp, errorx.New("回退万象会员积分成功", 0)
	}
	err = errorx.New("回退万象会员积分失败", 100099)
	return nil, err
}
